package com.batchengine.rssfeed.util;

/**
 * Created by sunil.kalva@mkhoj.com.
 * User: sunil.kalva
 * Date: Dec 6, 2009
 */

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;

public class RSSFeedParserSTAX {

    static final String CHANNEL = "channel";
    static final String TITLE = "title";
    static final String DESCRIPTION = "description";
    static final String LANGUAGE = "language";
    static final String CATEGORY = "category";
    static final String COPYRIGHT = "copyright";
    static final String LINK = "link";
    static final String AUTHOR = "author";

    static final String IMAGE = "image";
    static final String IMAGE_URL = "url";
    static final String IMAGE_WIDTH = "width";
    static final String IMAGE_HEIGHT = "height";


    static final String ITEM = "item";
    static final String PUB_DATE = "pubDate";
    static final String GUID = "guid";

    final URL url;

    final static Pattern pattern = compile("(?m)$^|[\\r\\n]+\\z");

    public RSSFeedParserSTAX(String feedUrl) {
        try {
            this.url = new URL(feedUrl);
        } catch(MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    public Feed readFeed() {

        Feed feed = null;
        try {

            boolean isFeedHeader = true;
            boolean isImageHeader = false;

            // Set header values intial to the empty string
            String description = "";
            String title = "";
            String link = "";
            String language = "";
            String copyright = "";
            String author = "";
            String pubdate = "";
            String guid = "";
            String category = "";
            Image image = null;
            String imageUrl = "";
            long width = 0l;
            long height = 0l;
            boolean descriptionStarted = false;

            // First create a new XMLInputFactory
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            inputFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
            // Setup a new eventReader
            InputStream in = read();

            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
            // Read the XML document
            while(eventReader.hasNext()) {

                XMLEvent event = eventReader.nextEvent();

                if(event.isStartElement()) {
                    if(event.asStartElement().getName().getLocalPart().equals(ITEM)) {
                        if(isFeedHeader) {
                            isFeedHeader = false;
                            feed = new Feed(title, link, description.trim(), language, copyright, pubdate, category, image);
                        }
                        event = eventReader.nextEvent();
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(IMAGE)) {
                        isImageHeader = true;
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(IMAGE_URL)) {
                        event = eventReader.nextEvent();
                        imageUrl = event.asCharacters().getData();
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(IMAGE_WIDTH)) {
                        event = eventReader.nextEvent();
                        if(null != event.asCharacters() && null != event.asCharacters().getData()) {
                            width = Long.parseLong(event.asCharacters().getData());
                        }
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(IMAGE_HEIGHT)) {
                        event = eventReader.nextEvent();
                        if(null != event.asCharacters() && null != event.asCharacters().getData()) {
                            height = Long.parseLong(event.asCharacters().getData());
                        }
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(TITLE)) {
                        event = eventReader.nextEvent();
                        title = event.asCharacters().getData();
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(DESCRIPTION)) {
                        event = eventReader.nextEvent();
                        description = event.asCharacters().getData();
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(LINK)) {
                        event = eventReader.nextEvent();
                        link = event.asCharacters().getData();
                        continue;
                    }

                    if(event.asStartElement().getName().getLocalPart().equals(GUID)) {
                        event = eventReader.nextEvent();
                        guid = event.asCharacters().getData();
                        continue;
                    }
                    if(event.asStartElement().getName().getLocalPart().equals(LANGUAGE)) {
                        event = eventReader.nextEvent();
                        language = event.asCharacters().getData();
                        continue;
                    }
                    if(event.asStartElement().getName().getLocalPart().equals(CATEGORY)) {
                        event = eventReader.nextEvent();
                        category = event.asCharacters().getData();
                        continue;
                    }
                    if(event.asStartElement().getName().getLocalPart().equals(AUTHOR)) {
                        event = eventReader.nextEvent();
                        author = event.asCharacters().getData();
                        continue;
                    }
                    if(event.asStartElement().getName().getLocalPart().equals(PUB_DATE)) {
                        event = eventReader.nextEvent();
                        pubdate = event.asCharacters().getData();
                        continue;
                    }
                    if(event.asStartElement().getName().getLocalPart().equals(COPYRIGHT)) {
                        event = eventReader.nextEvent();
                        copyright = event.asCharacters().getData();
                    }
                } else if(event.isEndElement()) {

                    if(event.asEndElement().getName().getLocalPart().equals(IMAGE)) {
                        isImageHeader = false;
                        image = new Image(title, imageUrl, width, height, link);
                        event = eventReader.nextEvent();
                        continue;
                    }

                    if(event.asEndElement().getName().getLocalPart().equals(ITEM)) {
                        FeedMessage message = new FeedMessage();
                        message.setAuthor(author);
                        Matcher matcher = pattern.matcher(description);
                        message.setDescription(matcher.replaceAll(""));
                        message.setGuid(guid);
                        message.setLink(link);
                        message.setTitle(title);
                        message.setCategory(category);
                        feed.getMessages().add(message);
                        event = eventReader.nextEvent();
                    }
                }
            }
        } catch(XMLStreamException e) {
            throw new RuntimeException(e);
        }
        return feed;

    }

    private InputStream read() {
        try {
            return url.openStream();
        } catch(IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {

        RSSFeedParserSTAX parser = new RSSFeedParserSTAX("http://www.kk.org/cooltools/index.xml");
//        RSSFeedParserSTAX parser = new RSSFeedParserSTAX("http://news.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml");
        Feed feed = parser.readFeed();
        System.out.println(feed);
        for(FeedMessage message : feed.getMessages()) {
            System.out.println(message);
        }
    }
}
